# 导入必要包
import cv2
import matplotlib.pyplot as plt
import numpy as np
# %matplotlib inline

# 采集图片位置：./images/行书/丙/敬世江_dddddd.jpg'
# 任务 将书法图片分成五类

# 读取数据
# 提取hog特征
# 送至svm训练
# 评估模型
# 保存模型
# 可视化看一下训练效果

# img_1 = cv2.imread('./images/行书/丙/敬世江_dddddd.jpg')
# # imread 不能读取中文路径
# plt.imshow(img_1)
def readImg(filePath):
    raw_data = np.fromfile(filePath, dtype=np.uint8)
    img = cv2.imdecode(raw_data,-1)
    return img
img_1 = readImg('./images/行书/丙/敬世江_dddddd.jpg')
img_1_fixed = cv2.cvtColor(img_1,cv2.COLOR_BGR2RGB)
plt.imshow(img_1_fixed)

# 提取hog特征
 
from skimage.feature import hog
from skimage import data,exposure

img_1_gray = cv2.cvtColor(cv2.resize(img_1,(200,200)),cv2.COLOR_BGR2GRAY)
plt.imshow(img_1_gray,cmap='gray')
fd, hog_img= hog(image=img_1_gray,
                 orientation=9,
                 pixels_per_cell=(8,8),
                 cells_per_block=(2,2),
                 visualize=True)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4), sharex=True, sharey=True)

ax1.axis('off')
ax1.imshow(img_1_fixed, cmap=plt.cm.gray)
ax1.set_title('Input image')

# Rescale histogram for better display
hog_image_rescaled = exposure.rescale_intensity(hog_img, in_range=(0, 10))

ax2.axis('off')
ax2.imshow(hog_image_rescaled, cmap=plt.cm.gray)
ax2.set_title('Histogram of Oriented Gradients')
plt.show()

# 批量读取文件数据
# 提取HOG特征

# 批量读取文件数据 需要一个列出路径下所有文件的工具
import os 
import glob
# *是通配符
# glob.glob('./images/行书/*/*56d.jpg')
list_1 = glob.glob('./images/行书/*/*')
len (list_1)

# 解析几种风格下的文件名
style_list = ['篆书','隶书','草书' ,'行书','楷书']

import random

feature_list = []
label_list=[]

# 打开图片,缩放，灰度
def imgOpenResizeGray(filePath):
    img_1 = readImg(filePath)
    img_1 = cv2.cvtColor(
        cv2.resize(img_1,(200,200)),
        cv2.COLOR_BGR2GRAY
        )
    return img_1


for style in style_list:
    print('style:{style}'.format(style=style))
    # 列出该风格下的所有文件
    file_list = glob.glob('./images/'+style+'/*/*')
    # 打乱并只保留前1000个文件
    random.shuffle(file_list)
    file_list = file_list[:100]

    # 遍历文件名列表
    for file_item in file_list:
        # 打开图片,缩放，灰度
        img_gray = imgOpenResizeGray(file_item)
        # 特征提取
        fd = hog(image=img_gray,
                 orientations=4,
                 pixels_per_cell=(6,6),
                 cells_per_block=(2,2),
                 visualize=False)
        
        # 提取图片类别索引
        label = style_list.index(style)

        # 放入特征和标签列表
        feature_list.append(fd)
        label_list.append(label)

# 导入svm 模型

from sklearn import svm

from sklearn.model_selection import train_test_split

# 将样本分为测试和训练样本
# 训练样本对应特征 测试样本特征 训练样本的标签 测试样本的标签
x_train,            x_test,     y_train,    y_test=train_test_split(feature_list,
                                                                    label_list,
                                                                    test_size=0.2,
                                                                    random_state=42)
# 训练
# 默认核函数效果一般般   有 rbf linear poly
# poly效果最好
cls = svm.SVC(kernel='poly')
cls.fit(x_train,y_train)
predicted_labels = cls.predict(x_test)

from skelearn.metrics import accuracy_score

# 算一下准确率
accuracy_score(y_test,predicted_labels)
# 基本都在0.6几 为什么那么低 
# 因为前面样本数量太少 L90：file_list = file_list[:100]

# 保存训练好的模型
from joblib import dump,load
dump(cls,'./models/poly.joblib')

# 加载训练后的模型
new_cls = load('./models/poly.joblib')
# 预测
predicted_labels = new_cls.predict(x_test)
accuracy_score(y_test,predicted_labels)

# 看整体评估效果如何 
from sklearn.metrics import confusion_matrix
# 混合矩阵 混淆矩阵 融合矩阵
cm = confusion_matrix(y_test,predicted_labels)
print(cm)

# 上面这种方式开起来不太直观
# 混淆矩阵可视化
import seaborn as sn
import pandas as pd
df_cm = pd.DataFrame(cm, index = [i for i in ['Zhuan','Li','Cao','Xing','Kai']],
                  columns = [i for i in ['Zhuan','Li','Cao','Xing','Kai']])
plt.figure(figsize = (10,7))
sn.heatmap(df_cm, annot=True,cmap="Greens",fmt="d")
